/**************************************************************************************************
* Title: SumVector2_16f.inl
* Author: Gael Huber
* Description: Implementation of 16-byte aligned Vector2 struct and related functions
**************************************************************************************************/

/**************************************************************************************************
* Default constructor
**************************************************************************************************/
inline Vector2_16f::Vector2_16f(void)
	: v(_mm_setzero_ps())
{ }

/**************************************************************************************************
* Constructor from vector
**************************************************************************************************/
inline Vector2_16f::Vector2_16f(__m128 f)
	: v(f)
{ }

/**************************************************************************************************
* Constructor from array
**************************************************************************************************/
inline Vector2_16f::Vector2_16f(const float* f)
	: v(_mm_set_ps(0.0f, 0.0f, f[1], f[0]))
{ }

/**************************************************************************************************
* Constructor specifying values
**************************************************************************************************/
inline Vector2_16f::Vector2_16f(float x, float y)
	: v(_mm_set_ps(0.0f, 0.0f, y, x))
{ }

/**************************************************************************************************
* Copy constructor
**************************************************************************************************/
inline Vector2_16f::Vector2_16f(const Vector2_16f& rhs)
	: v(rhs.v)
{ }

/**************************************************************************************************
* Destructor
**************************************************************************************************/
inline Vector2_16f::~Vector2_16f(void)
{ }

/**************************************************************************************************
* Cast to non-const
**************************************************************************************************/
inline Vector2_16f::operator float*(void) {
	return (float*) this;
}

/**************************************************************************************************
* Cast to const
**************************************************************************************************/
inline Vector2_16f::operator const float*(void) const {
	return (const float*) this;
}

/**************************************************************************************************
* Assignment operator
**************************************************************************************************/
inline Vector2_16f& Vector2_16f::operator=(const Vector2_16f& rhs) {
	// Self-assignment guard
	if(this == &rhs)
		return *this;

	// Copy and return
	v = rhs.v;

	return *this;
}

/**************************************************************************************************
* Addition assignment operator
**************************************************************************************************/
inline Vector2_16f& Vector2_16f::operator+=(const Vector2_16f& rhs) {
	v = _mm_add_ps(v, rhs.v);
	return *this;
}

/**************************************************************************************************
* Subtraction assignment operator
**************************************************************************************************/
inline Vector2_16f& Vector2_16f::operator-=(const Vector2_16f& rhs) {
	v = _mm_sub_ps(v, rhs.v);
	return *this;
}

/**************************************************************************************************
* Multiplication assignment operator
**************************************************************************************************/
inline Vector2_16f& Vector2_16f::operator*=(float rhs) {
	v = _mm_mul_ps(v, _mm_set1_ps(rhs));
	return *this;
}

/**************************************************************************************************
* Division assignment operator
**************************************************************************************************/
inline Vector2_16f& Vector2_16f::operator/=(float rhs) {
	v = _mm_div_ps(v, _mm_set1_ps(rhs));
	return *this;
}

/**************************************************************************************************
* Return a positive version of the vector
**************************************************************************************************/
inline Vector2_16f Vector2_16f::operator+(void) const {
	return *this;
}

/**************************************************************************************************
* Return a negated version of the vector
**************************************************************************************************/
inline Vector2_16f Vector2_16f::operator-(void) const {
	return Vector2_16f(-x, -y);
}

/**************************************************************************************************
* Return the sum of two vectors
**************************************************************************************************/
inline Vector2_16f Vector2_16f::operator+(const Vector2_16f& rhs) const {
	return Vector2_16f(_mm_add_ps(v, rhs.v));
}

/**************************************************************************************************
* Return difference between two vectors
**************************************************************************************************/
inline Vector2_16f Vector2_16f::operator-(const Vector2_16f& rhs) const {
	return Vector2_16f(_mm_sub_ps(v, rhs.v));
}

/**************************************************************************************************
* Multiply by a value
**************************************************************************************************/
inline Vector2_16f Vector2_16f::operator*(float rhs) const {
	return Vector2_16f(_mm_mul_ps(v, _mm_set1_ps(rhs)));
}

/**************************************************************************************************
* Divide by a value
**************************************************************************************************/
inline Vector2_16f Vector2_16f::operator/(float rhs) const {
	return Vector2_16f(_mm_div_ps(v, _mm_set1_ps(rhs)));
}

/**************************************************************************************************
* Multiply by a value
**************************************************************************************************/
inline Vector2_16f operator*(float lhs, const Vector2_16f& rhs) {
	return Vector2_16f(_mm_mul_ps(rhs.v, _mm_set1_ps(lhs)));
}

/**************************************************************************************************
* Equivalence
**************************************************************************************************/
inline bool Vector2_16f::operator==(const Vector2_16f& rhs) const {
	return (x == rhs.x && y == rhs.y);
}

/**************************************************************************************************
* Non-equivalence
**************************************************************************************************/
inline bool Vector2_16f::operator!=(const Vector2_16f& rhs) const {
	return (x != rhs.x || y != rhs.y);
}

/**************************************************************************************************
* Length
**************************************************************************************************/
inline float Vec2Length_16f(const Vector2_16f* pV) {
	return sqrtf(pV->x*pV->x + pV->y*pV->y);
}

/**************************************************************************************************
* Squared length
**************************************************************************************************/
inline float Vec2LengthSqr_16f(const Vector2_16f* pV) {
	return pV->x*pV->x + pV->y*pV->y;
}

/**************************************************************************************************
* Dot product
**************************************************************************************************/
inline float Vec2Dot_16f(const Vector2_16f* pV1, const Vector2_16f* pV2) {
	return pV1->x*pV2->x + pV1->y*pV2->y;
}

/**************************************************************************************************
* Z component of cross product
**************************************************************************************************/
inline float Vec2CCW_16f(const Vector2_16f* pV1, const Vector2_16f* pV2) {
	return pV1->x*pV2->y - pV1->y*pV2->x;
}

/**************************************************************************************************
* Addition
**************************************************************************************************/
inline Vector2_16f* Vec2Add_16f(Vector2_16f* pOut, const Vector2_16f* pV1, const Vector2_16f* pV2) {
	pOut->v = _mm_add_ps(pV1->v, pV2->v);
	return pOut;
}

/**************************************************************************************************
* Subtraction
**************************************************************************************************/
inline Vector2_16f* Vec2Sub_16f(Vector2_16f* pOut, const Vector2_16f* pV1, const Vector2_16f* pV2) {
	pOut->v = _mm_sub_ps(pV1->v, pV2->v);
	return pOut;
}

/**************************************************************************************************
* Minimize each component
**************************************************************************************************/
inline Vector2_16f* Vec2Minimize_16f(Vector2_16f* pOut, const Vector2_16f* pV1, const Vector2_16f* pV2) {
	pOut->v = _mm_min_ps(pV1->v, pV2->v);
	return pOut;
}

/**************************************************************************************************
* Maximize each component
**************************************************************************************************/
inline Vector2_16f* Vec2Maximize_16f(Vector2_16f* pOut, const Vector2_16f* pV1, const Vector2_16f* pV2) {
	pOut->v = _mm_max_ps(pV1->v, pV2->v);
	return pOut;
}

/**************************************************************************************************
* Scale the vector
**************************************************************************************************/
inline Vector2_16f* Vec2Scale_16f(Vector2_16f* pOut, const Vector2_16f* pV, float s) {
	pOut->v = _mm_mul_ps(pV->v, _mm_set1_ps(s));
	return pOut;
}

/**************************************************************************************************
* Linear interpolation V1 + s(V2 - V1)
**************************************************************************************************/
inline Vector2_16f* Vec2Lerp_16f(Vector2_16f* pOut, const Vector2_16f* pV1, const Vector2_16f* pV2, float s) {
	pOut->v = _mm_add_ps(pV1->v, _mm_mul_ps(_mm_set1_ps(s), _mm_sub_ps(pV2->v, pV1->v)));
	return pOut;
}

/**************************************************************************************************
* Normalize
**************************************************************************************************/
inline Vector2_16f* Vec2Normalize_16f(Vector2_16f* pOut, const Vector2_16f* pV) {
	pOut->v = _mm_div_ps(pV->v, _mm_set1_ps(Vec2Length_16f(pV)));
	return pOut;
}
